/*******************************************************************************
 *
 * Copyright (c) 2000-2003 Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * - Neither name of Intel Corporation nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************/

/*!
 * \addtogroup UpnpSamples
 *
 * @{
 *
 * \file
 */

#define SAMPLE_UTIL_C

#include "sample_util.h"

#include <stdarg.h>
#include <stdio.h>

#if !UPNP_HAVE_TOOLS
#error "Need upnptools.h to compile samples ; try ./configure --enable-tools"
#endif

static int initialize_init = 1;
static int initialize_register = 1;

/*! Function pointers to use for displaying formatted strings.
 * Set on Initialization of device. */
print_string gPrintFun = NULL;
state_update gStateUpdateFun = NULL;

/*! mutex to control displaying of events */
ithread_mutex_t display_mutex;

int SampleUtil_Initialize(print_string print_function)
{
        if (initialize_init) {
                ithread_mutexattr_t attr;

                ithread_mutexattr_init(&attr);
                ithread_mutexattr_setkind_np(&attr, ITHREAD_MUTEX_RECURSIVE_NP);
                ithread_mutex_init(&display_mutex, &attr);
                ithread_mutexattr_destroy(&attr);
                /* To shut up valgrind mutex warning. */
                ithread_mutex_lock(&display_mutex);
                gPrintFun = print_function;
                ithread_mutex_unlock(&display_mutex);
                /* Finished initializing. */
                initialize_init = 0;
        }

        return UPNP_E_SUCCESS;
}

int SampleUtil_RegisterUpdateFunction(state_update update_function)
{
        if (initialize_register) {
                gStateUpdateFun = update_function;
                initialize_register = 0;
        }

        return UPNP_E_SUCCESS;
}

int SampleUtil_Finish()
{
        ithread_mutex_destroy(&display_mutex);
        gPrintFun = NULL;
        gStateUpdateFun = NULL;
        initialize_init = 1;
        initialize_register = 1;

        return UPNP_E_SUCCESS;
}

char *SampleUtil_GetElementValue(IXML_Element *element)
{
        IXML_Node *child = ixmlNode_getFirstChild((IXML_Node *)element);
        char *temp = NULL;

        if (child != 0 && ixmlNode_getNodeType(child) == eTEXT_NODE)
                temp = strdup(ixmlNode_getNodeValue(child));

        return temp;
}

IXML_NodeList *SampleUtil_GetFirstServiceList(IXML_Document *doc)
{
        IXML_NodeList *ServiceList = NULL;
        IXML_NodeList *servlistnodelist = NULL;
        IXML_Node *servlistnode = NULL;

        servlistnodelist =
                ixmlDocument_getElementsByTagName(doc, "serviceList");
        if (servlistnodelist && ixmlNodeList_length(servlistnodelist)) {
                /* we only care about the first service list, from the root
                 * device */
                servlistnode = ixmlNodeList_item(servlistnodelist, 0);
                /* create as list of DOM nodes */
                ServiceList = ixmlElement_getElementsByTagName(
                        (IXML_Element *)servlistnode, "service");
        }
        if (servlistnodelist)
                ixmlNodeList_free(servlistnodelist);

        return ServiceList;
}

#define OLD_FIND_SERVICE_CODE
#ifdef OLD_FIND_SERVICE_CODE
#else
/*
 * Obtain the service list
 *    n == 0 the first
 *    n == 1 the next in the device list, etc..
 */
static IXML_NodeList *SampleUtil_GetNthServiceList(
        /*! [in] . */
        IXML_Document *doc,
        /*! [in] . */
        unsigned int n)
{
        IXML_NodeList *ServiceList = NULL;
        IXML_NodeList *servlistnodelist = NULL;
        IXML_Node *servlistnode = NULL;

        /*  ixmlDocument_getElementsByTagName()
         *  Returns a NodeList of all Elements that match the given
         *  tag name in the order in which they were encountered in a preorder
         *  traversal of the Document tree.
         *
         *  return (NodeList*) A pointer to a NodeList containing the
         *                      matching items or NULL on an error. 	 */
        SampleUtil_Print("SampleUtil_GetNthServiceList called : n = %d\n", n);
        servlistnodelist =
                ixmlDocument_getElementsByTagName(doc, "serviceList");
        if (servlistnodelist && ixmlNodeList_length(servlistnodelist) &&
                n < ixmlNodeList_length(servlistnodelist)) {
                /* For the first service list (from the root device),
                 * we pass 0 */
                /*servlistnode = ixmlNodeList_item( servlistnodelist, 0 );*/

                /* Retrieves a Node from a NodeList} specified by a
                 *  numerical index.
                 *
                 *  return (Node*) A pointer to a Node or NULL if there was an
                 *                  error. */
                servlistnode = ixmlNodeList_item(servlistnodelist, n);
                if (!servlistnode) {
                        /* create as list of DOM nodes */
                        ServiceList = ixmlElement_getElementsByTagName(
                                (IXML_Element *)servlistnode, "service");
                } else
                        SampleUtil_Print("%s(%d): ixmlNodeList_item(nodeList, "
                                         "n) returned NULL\n",
                                __FILE__,
                                __LINE__);
        }
        if (servlistnodelist)
                ixmlNodeList_free(servlistnodelist);

        return ServiceList;
}
#endif

char *SampleUtil_GetFirstDocumentItem(IXML_Document *doc, const char *item)
{
        IXML_NodeList *nodeList = NULL;
        IXML_Node *textNode = NULL;
        IXML_Node *tmpNode = NULL;
        const char *nodeValue = NULL;
        char *ret = NULL;

        nodeList = ixmlDocument_getElementsByTagName(doc, (char *)item);
        if (nodeList) {
                tmpNode = ixmlNodeList_item(nodeList, 0);
                if (tmpNode) {
                        textNode = ixmlNode_getFirstChild(tmpNode);
                        if (!textNode) {
                                SampleUtil_Print("%s(%d): (BUG) "
                                                 "ixmlNode_getFirstChild("
                                                 "tmpNode) returned NULL\n",
                                        __FILE__,
                                        __LINE__);
                                ret = strdup("");
                                goto epilogue;
                        }
                        nodeValue = ixmlNode_getNodeValue(textNode);
                        if (!nodeValue) {
                                SampleUtil_Print(
                                        "%s(%d): ixmlNode_getNodeValue "
                                        "returned NULL\n",
                                        __FILE__,
                                        __LINE__);
                                ret = strdup("");
                                goto epilogue;
                        }
                        ret = strdup(nodeValue);
                        if (!ret) {
                                SampleUtil_Print("%s(%d): Error allocating "
                                                 "memory for XML Node value\n",
                                        __FILE__,
                                        __LINE__);
                                ret = strdup("");
                        }
                } else
                        SampleUtil_Print("%s(%d): ixmlNodeList_item(nodeList, "
                                         "0) returned NULL\n",
                                __FILE__,
                                __LINE__);
        } else
                SampleUtil_Print("%s(%d): Error finding %s in XML Node\n",
                        __FILE__,
                        __LINE__,
                        item);

epilogue:
        if (nodeList)
                ixmlNodeList_free(nodeList);

        return ret;
}

char *SampleUtil_GetFirstElementItem(IXML_Element *element, const char *item)
{
        IXML_NodeList *nodeList = NULL;
        IXML_Node *textNode = NULL;
        IXML_Node *tmpNode = NULL;
        char *ret = NULL;

        nodeList = ixmlElement_getElementsByTagName(element, (char *)item);
        if (nodeList == NULL) {
                SampleUtil_Print("%s(%d): Error finding %s in XML Node\n",
                        __FILE__,
                        __LINE__,
                        item);
                return NULL;
        }
        tmpNode = ixmlNodeList_item(nodeList, 0);
        if (!tmpNode) {
                SampleUtil_Print("%s(%d): Error finding %s value in XML Node\n",
                        __FILE__,
                        __LINE__,
                        item);
                ixmlNodeList_free(nodeList);
                return NULL;
        }
        textNode = ixmlNode_getFirstChild(tmpNode);
        ret = strdup(ixmlNode_getNodeValue(textNode));
        if (!ret) {
                SampleUtil_Print(
                        "%s(%d): Error allocating memory for %s in XML Node\n",
                        __FILE__,
                        __LINE__,
                        item);
                ixmlNodeList_free(nodeList);
                return NULL;
        }
        ixmlNodeList_free(nodeList);

        return ret;
}

void SampleUtil_PrintEventType(Upnp_EventType S)
{
        switch (S) {
        /* Discovery */
        case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
                SampleUtil_Print("UPNP_DISCOVERY_ADVERTISEMENT_ALIVE\n");
                break;
        case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
                SampleUtil_Print("UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE\n");
                break;
        case UPNP_DISCOVERY_SEARCH_RESULT:
                SampleUtil_Print("UPNP_DISCOVERY_SEARCH_RESULT\n");
                break;
        case UPNP_DISCOVERY_SEARCH_TIMEOUT:
                SampleUtil_Print("UPNP_DISCOVERY_SEARCH_TIMEOUT\n");
                break;
        /* SOAP */
        case UPNP_CONTROL_ACTION_REQUEST:
                SampleUtil_Print("UPNP_CONTROL_ACTION_REQUEST\n");
                break;
        case UPNP_CONTROL_ACTION_COMPLETE:
                SampleUtil_Print("UPNP_CONTROL_ACTION_COMPLETE\n");
                break;
        case UPNP_CONTROL_GET_VAR_REQUEST:
                SampleUtil_Print("UPNP_CONTROL_GET_VAR_REQUEST\n");
                break;
        case UPNP_CONTROL_GET_VAR_COMPLETE:
                SampleUtil_Print("UPNP_CONTROL_GET_VAR_COMPLETE\n");
                break;
        /* GENA */
        case UPNP_EVENT_SUBSCRIPTION_REQUEST:
                SampleUtil_Print("UPNP_EVENT_SUBSCRIPTION_REQUEST\n");
                break;
        case UPNP_EVENT_RECEIVED:
                SampleUtil_Print("UPNP_EVENT_RECEIVED\n");
                break;
        case UPNP_EVENT_RENEWAL_COMPLETE:
                SampleUtil_Print("UPNP_EVENT_RENEWAL_COMPLETE\n");
                break;
        case UPNP_EVENT_SUBSCRIBE_COMPLETE:
                SampleUtil_Print("UPNP_EVENT_SUBSCRIBE_COMPLETE\n");
                break;
        case UPNP_EVENT_UNSUBSCRIBE_COMPLETE:
                SampleUtil_Print("UPNP_EVENT_UNSUBSCRIBE_COMPLETE\n");
                break;
        case UPNP_EVENT_AUTORENEWAL_FAILED:
                SampleUtil_Print("UPNP_EVENT_AUTORENEWAL_FAILED\n");
                break;
        case UPNP_EVENT_SUBSCRIPTION_EXPIRED:
                SampleUtil_Print("UPNP_EVENT_SUBSCRIPTION_EXPIRED\n");
                break;
        }
}

int SampleUtil_PrintEvent(Upnp_EventType EventType, const void *Event)
{
        ithread_mutex_lock(&display_mutex);

        SampleUtil_Print("====================================================="
                         "=================\n"
                         "-----------------------------------------------------"
                         "-----------------\n");
        SampleUtil_PrintEventType(EventType);
        switch (EventType) {
        /* SSDP */
        case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
        case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
        case UPNP_DISCOVERY_SEARCH_RESULT: {
                UpnpDiscovery *d_event = (UpnpDiscovery *)Event;
                SampleUtil_Print("ErrCode     =  %d\n"
                                 "Expires     =  %d\n"
                                 "DeviceId    =  %s\n"
                                 "DeviceType  =  %s\n"
                                 "ServiceType =  %s\n"
                                 "ServiceVer  =  %s\n"
                                 "Location    =  %s\n"
                                 "OS          =  %s\n"
                                 "Date        =  %s\n"
                                 "Ext         =  %s\n",
                        UpnpDiscovery_get_ErrCode(d_event),
                        UpnpDiscovery_get_Expires(d_event),
                        UpnpString_get_String(
                                UpnpDiscovery_get_DeviceID(d_event)),
                        UpnpString_get_String(
                                UpnpDiscovery_get_DeviceType(d_event)),
                        UpnpString_get_String(
                                UpnpDiscovery_get_ServiceType(d_event)),
                        UpnpString_get_String(
                                UpnpDiscovery_get_ServiceVer(d_event)),
                        UpnpString_get_String(
                                UpnpDiscovery_get_Location(d_event)),
                        UpnpString_get_String(UpnpDiscovery_get_Os(d_event)),
                        UpnpString_get_String(UpnpDiscovery_get_Date(d_event)),
                        UpnpString_get_String(UpnpDiscovery_get_Ext(d_event)));
                break;
        }
        case UPNP_DISCOVERY_SEARCH_TIMEOUT:
                /* Nothing to print out here */
                break;
        /* SOAP */
        case UPNP_CONTROL_ACTION_REQUEST: {
                UpnpActionRequest *a_event = (UpnpActionRequest *)Event;
                IXML_Document *actionRequestDoc = NULL;
                IXML_Document *actionResultDoc = NULL;
                char *xmlbuff = NULL;

                SampleUtil_Print("ErrCode     =  %d\n"
                                 "ErrStr      =  %s\n"
                                 "ActionName  =  %s\n"
                                 "UDN         =  %s\n"
                                 "ServiceID   =  %s\n",
                        UpnpActionRequest_get_ErrCode(a_event),
                        UpnpString_get_String(
                                UpnpActionRequest_get_ErrStr(a_event)),
                        UpnpString_get_String(
                                UpnpActionRequest_get_ActionName(a_event)),
                        UpnpString_get_String(
                                UpnpActionRequest_get_DevUDN(a_event)),
                        UpnpString_get_String(
                                UpnpActionRequest_get_ServiceID(a_event)));
                actionRequestDoc = UpnpActionRequest_get_ActionRequest(a_event);
                if (actionRequestDoc) {
                        xmlbuff = ixmlPrintNode((IXML_Node *)actionRequestDoc);
                        if (xmlbuff) {
                                SampleUtil_Print(
                                        "ActRequest  =  %s\n", xmlbuff);
                                ixmlFreeDOMString(xmlbuff);
                        }
                        xmlbuff = NULL;
                } else {
                        SampleUtil_Print("ActRequest  =  (null)\n");
                }
                actionResultDoc = UpnpActionRequest_get_ActionResult(a_event);
                if (actionResultDoc) {
                        xmlbuff = ixmlPrintNode((IXML_Node *)actionResultDoc);
                        if (xmlbuff) {
                                SampleUtil_Print(
                                        "ActResult   =  %s\n", xmlbuff);
                                ixmlFreeDOMString(xmlbuff);
                        }
                        xmlbuff = NULL;
                } else {
                        SampleUtil_Print("ActResult   =  (null)\n");
                }
                break;
        }
        case UPNP_CONTROL_ACTION_COMPLETE: {
                UpnpActionComplete *a_event = (UpnpActionComplete *)Event;
                char *xmlbuff = NULL;
                int errCode = UpnpActionComplete_get_ErrCode(a_event);
                const char *ctrlURL = UpnpString_get_String(
                        UpnpActionComplete_get_CtrlUrl(a_event));
                IXML_Document *actionRequest =
                        UpnpActionComplete_get_ActionRequest(a_event);
                IXML_Document *actionResult =
                        UpnpActionComplete_get_ActionResult(a_event);

                SampleUtil_Print("ErrCode     =  %d\n"
                                 "CtrlUrl     =  %s\n",
                        errCode,
                        ctrlURL);
                if (actionRequest) {
                        xmlbuff = ixmlPrintNode((IXML_Node *)actionRequest);
                        if (xmlbuff) {
                                SampleUtil_Print(
                                        "ActRequest  =  %s\n", xmlbuff);
                                ixmlFreeDOMString(xmlbuff);
                        }
                        xmlbuff = NULL;
                } else {
                        SampleUtil_Print("ActRequest  =  (null)\n");
                }
                if (actionResult) {
                        xmlbuff = ixmlPrintNode((IXML_Node *)actionResult);
                        if (xmlbuff) {
                                SampleUtil_Print(
                                        "ActResult   =  %s\n", xmlbuff);
                                ixmlFreeDOMString(xmlbuff);
                        }
                        xmlbuff = NULL;
                } else {
                        SampleUtil_Print("ActResult   =  (null)\n");
                }
                break;
        }
        case UPNP_CONTROL_GET_VAR_REQUEST: {
                UpnpStateVarRequest *sv_event = (UpnpStateVarRequest *)Event;

                SampleUtil_Print("ErrCode     =  %d\n"
                                 "ErrStr      =  %s\n"
                                 "UDN         =  %s\n"
                                 "ServiceID   =  %s\n"
                                 "StateVarName=  %s\n"
                                 "CurrentVal  =  %s\n",
                        UpnpStateVarRequest_get_ErrCode(sv_event),
                        UpnpString_get_String(
                                UpnpStateVarRequest_get_ErrStr(sv_event)),
                        UpnpString_get_String(
                                UpnpStateVarRequest_get_DevUDN(sv_event)),
                        UpnpString_get_String(
                                UpnpStateVarRequest_get_ServiceID(sv_event)),
                        UpnpString_get_String(
                                UpnpStateVarRequest_get_StateVarName(sv_event)),
                        UpnpStateVarRequest_get_CurrentVal(sv_event));
                break;
        }
        case UPNP_CONTROL_GET_VAR_COMPLETE: {
                UpnpStateVarComplete *sv_event = (UpnpStateVarComplete *)Event;

                SampleUtil_Print("ErrCode     =  %d\n"
                                 "CtrlUrl     =  %s\n"
                                 "StateVarName=  %s\n"
                                 "CurrentVal  =  %s\n",
                        UpnpStateVarComplete_get_ErrCode(sv_event),
                        UpnpString_get_String(
                                UpnpStateVarComplete_get_CtrlUrl(sv_event)),
                        UpnpString_get_String(
                                UpnpStateVarComplete_get_StateVarName(
                                        sv_event)),
                        UpnpStateVarComplete_get_CurrentVal(sv_event));
                break;
        }
        /* GENA */
        case UPNP_EVENT_SUBSCRIPTION_REQUEST: {
                UpnpSubscriptionRequest *sr_event =
                        (UpnpSubscriptionRequest *)Event;

                SampleUtil_Print("ServiceID   =  %s\n"
                                 "UDN         =  %s\n"
                                 "SID         =  %s\n",
                        UpnpString_get_String(
                                UpnpSubscriptionRequest_get_ServiceId(
                                        sr_event)),
                        UpnpString_get_String(
                                UpnpSubscriptionRequest_get_UDN(sr_event)),
                        UpnpString_get_String(
                                UpnpSubscriptionRequest_get_SID(sr_event)));
                break;
        }
        case UPNP_EVENT_RECEIVED: {
                UpnpEvent *e_event = (UpnpEvent *)Event;
                char *xmlbuff = NULL;

                xmlbuff = ixmlPrintNode(
                        (IXML_Node *)UpnpEvent_get_ChangedVariables(e_event));
                SampleUtil_Print("SID         =  %s\n"
                                 "EventKey    =  %d\n"
                                 "ChangedVars =  %s\n",
                        UpnpString_get_String(UpnpEvent_get_SID(e_event)),
                        UpnpEvent_get_EventKey(e_event),
                        xmlbuff);
                ixmlFreeDOMString(xmlbuff);
                break;
        }
        case UPNP_EVENT_RENEWAL_COMPLETE: {
                UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event;

                SampleUtil_Print("SID         =  %s\n"
                                 "ErrCode     =  %d\n"
                                 "TimeOut     =  %d\n",
                        UpnpString_get_String(
                                UpnpEventSubscribe_get_SID(es_event)),
                        UpnpEventSubscribe_get_ErrCode(es_event),
                        UpnpEventSubscribe_get_TimeOut(es_event));
                break;
        }
        case UPNP_EVENT_SUBSCRIBE_COMPLETE:
        case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: {
                UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event;

                SampleUtil_Print("SID         =  %s\n"
                                 "ErrCode     =  %d\n"
                                 "PublisherURL=  %s\n"
                                 "TimeOut     =  %d\n",
                        UpnpString_get_String(
                                UpnpEventSubscribe_get_SID(es_event)),
                        UpnpEventSubscribe_get_ErrCode(es_event),
                        UpnpString_get_String(
                                UpnpEventSubscribe_get_PublisherUrl(es_event)),
                        UpnpEventSubscribe_get_TimeOut(es_event));
                break;
        }
        case UPNP_EVENT_AUTORENEWAL_FAILED:
        case UPNP_EVENT_SUBSCRIPTION_EXPIRED: {
                UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event;

                SampleUtil_Print("SID         =  %s\n"
                                 "ErrCode     =  %d\n"
                                 "PublisherURL=  %s\n"
                                 "TimeOut     =  %d\n",
                        UpnpString_get_String(
                                UpnpEventSubscribe_get_SID(es_event)),
                        UpnpEventSubscribe_get_ErrCode(es_event),
                        UpnpString_get_String(
                                UpnpEventSubscribe_get_PublisherUrl(es_event)),
                        UpnpEventSubscribe_get_TimeOut(es_event));
                break;
        }
        }
        SampleUtil_Print("-----------------------------------------------------"
                         "-----------------\n"
                         "====================================================="
                         "=================\n"
                         "\n\n\n");

        ithread_mutex_unlock(&display_mutex);

        return 0;
}

int SampleUtil_FindAndParseService(UpnpLib *p,
        IXML_Document *DescDoc,
        const char *location,
        const char *serviceType,
        char **serviceId,
        char **eventURL,
        char **controlURL)
{
        unsigned int i;
        unsigned long length;
        int found = 0;
        int ret;
#ifdef OLD_FIND_SERVICE_CODE
#else /* OLD_FIND_SERVICE_CODE */
        unsigned int sindex = 0;
#endif /* OLD_FIND_SERVICE_CODE */
        char *tempServiceType = NULL;
        char *baseURL = NULL;
        const char *base = NULL;
        char *relcontrolURL = NULL;
        char *releventURL = NULL;
        IXML_NodeList *serviceList = NULL;
        IXML_Element *service = NULL;

        baseURL = SampleUtil_GetFirstDocumentItem(DescDoc, "URLBase");
        if (baseURL)
                base = baseURL;
        else
                base = location;
#ifdef OLD_FIND_SERVICE_CODE
        serviceList = SampleUtil_GetFirstServiceList(DescDoc);
#else /* OLD_FIND_SERVICE_CODE */
        for (sindex = 0; (serviceList = SampleUtil_GetNthServiceList(
                                  DescDoc, sindex)) != NULL;
                sindex++) {
                tempServiceType = NULL;
                relcontrolURL = NULL;
                releventURL = NULL;
                service = NULL;
#endif /* OLD_FIND_SERVICE_CODE */
        length = ixmlNodeList_length(serviceList);
        for (i = 0; i < length; i++) {
                service = (IXML_Element *)ixmlNodeList_item(serviceList, i);
                tempServiceType = SampleUtil_GetFirstElementItem(
                        (IXML_Element *)service, "serviceType");
                if (tempServiceType &&
                        strcmp(tempServiceType, serviceType) == 0) {
                        SampleUtil_Print("Found service: %s\n", serviceType);
                        *serviceId = SampleUtil_GetFirstElementItem(
                                service, "serviceId");
                        SampleUtil_Print("serviceId: %s\n", *serviceId);
                        relcontrolURL = SampleUtil_GetFirstElementItem(
                                service, "controlURL");
                        releventURL = SampleUtil_GetFirstElementItem(
                                service, "eventSubURL");
                        ret = UpnpResolveURL2(
                                p, base, relcontrolURL, controlURL);
                        if (ret != UPNP_E_SUCCESS)
                                SampleUtil_Print("Error generating controlURL "
                                                 "from %s + %s\n",
                                        base,
                                        relcontrolURL);
                        ret = UpnpResolveURL2(p, base, releventURL, eventURL);
                        if (ret != UPNP_E_SUCCESS)
                                SampleUtil_Print("Error generating eventURL "
                                                 "from %s + %s\n",
                                        base,
                                        releventURL);
                        free(relcontrolURL);
                        free(releventURL);
                        relcontrolURL = NULL;
                        releventURL = NULL;
                        found = 1;
                        break;
                }
                free(tempServiceType);
                tempServiceType = NULL;
        }
        free(tempServiceType);
        tempServiceType = NULL;
        if (serviceList)
                ixmlNodeList_free(serviceList);
        serviceList = NULL;
#ifdef OLD_FIND_SERVICE_CODE
#else /* OLD_FIND_SERVICE_CODE */
        }
#endif /* OLD_FIND_SERVICE_CODE */
        free(baseURL);

        return found;
}

int SampleUtil_Print(const char *fmt, ...)
{
#define MAX_BUF (8 * 1024)
        va_list ap;
        static char buf[MAX_BUF];
        int rc;

        /* Protect both the display and the static buffer with the mutex */
        ithread_mutex_lock(&display_mutex);

        va_start(ap, fmt);
        rc = vsnprintf(buf, MAX_BUF, fmt, ap);
        va_end(ap);
        if (gPrintFun)
                gPrintFun("%s", buf);

        ithread_mutex_unlock(&display_mutex);

        return rc;
}

void SampleUtil_StateUpdate(const char *varName,
        const char *varValue,
        const char *UDN,
        eventType type)
{
        /* TBD: Add mutex here? */
        if (gStateUpdateFun)
                gStateUpdateFun(varName, varValue, UDN, type);
}

/*!
 * \brief Prints a string to standard out.
 */
void linux_print(const char *format, ...)
{
        va_list argList;

        va_start(argList, format);
        vfprintf(stdout, format, argList);
        fflush(stdout);
        va_end(argList);
}

/*! @} UpnpSamples */
